import numpy
from mpl_toolkits.mplot3d import Axes3D
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import scale
import matplotlib.pyplot as plt

# 生成数据
data = load_breast_cancer()
X, y = scale(data['data'][:, :2]), data['target']
# 根据数据利用逻辑回归得到参数值 （求出两个维度对应的数据在逻辑回归算法下的最优解）
lr = LogisticRegression(fit_intercept=False)
lr.fit(X, y)
theta_1 = lr.coef_[0, 0]
theta_2 = lr.coef_[0, 1]
print(theta_1, theta_2)


# 求已知 W1 和 W2 的情况下，传进来数据的 X，返回数据的 y_predict
def y_predict(X_, w1, w2):
    z = X_[0] * w1 + X_[1] * w2
    return 1 / (1 + numpy.exp(-z))


# 设置theta1 和 theta2 浮动值
theta_1_range = numpy.linspace(theta_1 - 0.6, theta_1 + 0.6, 50)
theta_2_range = numpy.linspace(theta_2 - 0.6, theta_2 + 0.6, 50)


def loss_function(X_d, y_d, w1, w2):
    result = 0
    for x_, y_ in zip(X_d, y_d):
        y_result = y_predict(x_, w1, w2)
        loss_result = -1 * y_ * numpy.log(y_result) - (1 - y_) * numpy.log(1 - y_result)
        result += loss_result
    return result


# 利用浮动范围的theta1 和 theta2 求的各自的损失函数
theta_1_range_loss = numpy.array([loss_function(X, y, i, theta_2) for i in theta_1_range])
theta_2_range_loss = numpy.array([loss_function(X, y, theta_1, i) for i in theta_2_range])

plt.subplot(2, 2, 1)
plt.plot(theta_1_range, theta_1_range_loss, 'b-', label='Theta1 Loss')
plt.plot(theta_2_range, theta_2_range_loss, 'r-', label='Theta2 Loss')
# 显示图例
plt.legend()
# 标题和坐标轴
plt.title("Loss Function vs. Theta Parameters")  # 图表标题
plt.xlabel("Parameter Value")  # x轴标签
plt.ylabel("Loss")  # y轴标签

plt.subplot(2, 2, 2)
# 得到网格
theta_1_range_grid, theta_2_range_grid = numpy.meshgrid(theta_1_range, theta_2_range)
loss_grid = loss_function(X, y, theta_1_range_grid, theta_2_range_grid)
plt.contour(theta_1_range_grid, theta_2_range_grid, loss_grid)
plt.subplot(2, 2, 4)
plt.contour(theta_1_range_grid, theta_2_range_grid, loss_grid, 30)

fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')

# 绘制曲面（颜色映射表示高度）
surf = ax.plot_surface(
    theta_1_range_grid,
    theta_2_range_grid,
    loss_grid,
    cmap='viridis',  # 颜色映射
    edgecolor='none',  # 隐藏网格线
    alpha=0.8  # 透明度
)

# 添加颜色条
fig.colorbar(surf, ax=ax, shrink=0.5, label='Loss')

# 设置标签和标题
ax.set_xlabel('θ₁')
ax.set_ylabel('θ₂')
ax.set_zlabel('Loss')
ax.set_title('3D Loss Function Surface')

plt.show()
